<template>
  <div class="record-page">
    <el-card shadow="never" class="search-card">
      <div class="search-header">
        <div class="search-header__title">
          <el-icon class="search-header__icon">
            <Collection />
          </el-icon>
          <div>
            <p class="search-header__subtitle">仓库管理 · 产品出入库</p>
            <h2 class="search-header__heading">产品出入库记录</h2>
          </div>
        </div>
        <div class="search-header__actions">
          <el-button :icon="RefreshLeft" @click="handleReset">重置</el-button>
          <el-button
            type="primary"
            :icon="Search"
            :loading="currentLoading"
            @click="handleSearch"
          >
            查询
          </el-button>
        </div>
      </div>
      <el-form :inline="true" :model="searchForm" class="search-form">
        <el-form-item label="产品编号/名称">
          <el-input
            v-model="searchForm.keyword"
            placeholder="请输入产品编号或名称"
            clearable
            class="search-input"
            @keyup.enter="handleSearch"
          >
            <template #prefix>
              <el-icon><Tickets /></el-icon>
            </template>
          </el-input>
        </el-form-item>
        <el-form-item label="产品类型">
          <el-select
            v-model="searchForm.productType"
            placeholder="全部"
            clearable
            class="search-input"
            :loading="loadingMeta"
          >
            <el-option
              v-for="option in productTypeOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="产品属性">
          <el-select
            v-model="searchForm.productAttribute"
            placeholder="全部"
            clearable
            class="search-input"
            :loading="loadingMeta"
          >
            <el-option
              v-for="option in productAttributeOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="产品分类">
          <el-select
            v-model="searchForm.productCategory"
            placeholder="全部"
            clearable
            class="search-input"
            :loading="loadingMeta"
          >
            <el-option
              v-for="option in productCategoryOptions"
              :key="option.value"
              :label="option.label"
              :value="option.value"
            />
          </el-select>
        </el-form-item>
      </el-form>
    </el-card>

    <el-card shadow="never" class="tabs-card">
      <el-tabs v-model="activeTab" @tab-change="handleTabChange">
        <el-tab-pane label="入库记录" name="inbound">
          <div class="tab-toolbar">
            <div class="tab-toolbar__info">
              <h3>
                <el-icon><Box /></el-icon>
                入库记录列表
              </h3>
              <p>
                共
                <strong>{{ inboundState.pagination.totalCount }}</strong>
                条记录
                <span v-if="hasMetaFilter"
                  >（过滤后展示 {{ inboundDisplayList.length }} 条）</span
                >
              </p>
            </div>
            <el-button
              type="success"
              :icon="Download"
              :loading="inboundState.exportLoading"
              @click="handleExport('inbound')"
            >
              导出
            </el-button>
          </div>
          <el-table
            v-loading="inboundState.loading"
            :data="inboundDisplayList"
            border
            stripe
            class="record-table"
          >
            <el-table-column
              type="index"
              label="序号"
              width="70"
              :index="(index: number) => getIndex('inbound', index)"
              align="center"
            />
            <el-table-column
              prop="productName"
              label="产品名称"
              min-width="150"
            />
            <el-table-column
              prop="productNo"
              label="产品编号"
              min-width="140"
            />
            <el-table-column
              prop="specification"
              label="规格型号"
              min-width="140"
            />
            <el-table-column
              prop="unit"
              label="单位"
              width="90"
              align="center"
            />
            <el-table-column prop="batchNo" label="批次号" min-width="120" />
            <el-table-column label="有效期" min-width="120">
              <template #default="{ row }">
                {{ formatDate(row.expiryDate) }}
              </template>
            </el-table-column>
            <el-table-column label="入库日期" min-width="120">
              <template #default="{ row }">
                {{ formatDate(row.inboundDate) }}
              </template>
            </el-table-column>
            <el-table-column
              prop="inboundQuantity"
              label="入库数量"
              min-width="110"
              align="right"
            />
            <el-table-column
              prop="warehouseName"
              label="仓库名称"
              min-width="140"
            />
            <el-table-column
              prop="warehouseAreaName"
              label="库区名称"
              min-width="140"
            />
            <el-table-column
              prop="warehouseLocationName"
              label="库位名称"
              min-width="140"
            />
            <el-table-column
              prop="workOrderName"
              label="工单名称"
              min-width="150"
            />
            <el-table-column
              prop="workOrderNo"
              label="工单编号"
              min-width="150"
            />
            <template #empty>
              <div class="empty-block">
                <p>暂无入库记录</p>
                <span>切换查询条件或稍后再试</span>
              </div>
            </template>
          </el-table>
          <div class="table-pagination">
            <div class="pagination-wrapper">
              <div class="pagination-info">
                <div class="pagination-info-item">
                  <el-icon class="info-icon"><Document /></el-icon>
                  <span class="pagination-text">
                    共
                    <span class="highlight-number">{{
                      inboundState.pagination.totalCount
                    }}</span>
                    条记录
                  </span>
                </div>
                <div class="pagination-info-item">
                  <el-icon class="info-icon"><Files /></el-icon>
                  <span class="pagination-text">
                    第
                    <span class="highlight-number">{{
                      inboundState.pagination.pageIndex
                    }}</span>
                    /
                    <span class="highlight-number">{{
                      inboundState.pagination.pageCount || 1
                    }}</span>
                    页
                  </span>
                </div>
              </div>
              <div class="pagination-controls">
                <el-button
                  size="small"
                  @click="gotoFirst('inbound')"
                  :disabled="inboundState.pagination.pageIndex === 1"
                  class="pagination-btn pagination-btn-first"
                >
                  首页
                </el-button>
                <el-button
                  size="small"
                  @click="gotoPrev('inbound')"
                  :disabled="inboundState.pagination.pageIndex === 1"
                  class="pagination-btn"
                >
                  上一页
                </el-button>
                <el-pagination
                  v-model:current-page="inboundState.pagination.pageIndex"
                  v-model:page-size="inboundState.pagination.pageSize"
                  :total="inboundState.pagination.totalCount"
                  layout="prev, pager, next"
                  :page-sizes="[10, 20, 30, 50]"
                  @current-change="(val: number) => handleCurrentChange('inbound', val)"
                  class="pagination-component"
                />
                <el-button
                  size="small"
                  @click="gotoNext('inbound')"
                  :disabled="
                    inboundState.pagination.pageIndex >=
                    inboundState.pagination.pageCount
                  "
                  class="pagination-btn"
                >
                  下一页
                </el-button>
                <el-button
                  size="small"
                  @click="gotoLast('inbound')"
                  :disabled="
                    inboundState.pagination.pageIndex >=
                    inboundState.pagination.pageCount
                  "
                  class="pagination-btn pagination-btn-last"
                >
                  尾页
                </el-button>
                <el-select
                  v-model="inboundState.pagination.pageSize"
                  size="small"
                  class="page-size-select"
                  @change="(val: number) => handleSizeChange('inbound', val)"
                >
                  <el-option label="10条/页" :value="10" />
                  <el-option label="20条/页" :value="20" />
                  <el-option label="30条/页" :value="30" />
                  <el-option label="50条/页" :value="50" />
                </el-select>
                <span class="pagination-jumper">前往</span>
                <el-input-number
                  v-model="inboundJumpPage"
                  :min="1"
                  :max="inboundState.pagination.pageCount || 1"
                  :controls="false"
                  size="small"
                  class="jump-input"
                  @keyup.enter="handleJumpPage('inbound')"
                />
                <span class="pagination-jumper">页</span>
              </div>
            </div>
          </div>
        </el-tab-pane>

        <el-tab-pane label="出库记录" name="outbound">
          <div class="tab-toolbar">
            <div class="tab-toolbar__info">
              <h3>
                <el-icon><Operation /></el-icon>
                出库记录列表
              </h3>
              <p>
                共
                <strong>{{ outboundState.pagination.totalCount }}</strong>
                条记录
                <span v-if="hasMetaFilter"
                  >（过滤后展示 {{ outboundDisplayList.length }} 条）</span
                >
              </p>
            </div>
            <el-button
              type="success"
              :icon="Download"
              :loading="outboundState.exportLoading"
              @click="handleExport('outbound')"
            >
              导出
            </el-button>
          </div>
          <el-table
            v-loading="outboundState.loading"
            :data="outboundDisplayList"
            border
            stripe
            class="record-table"
          >
            <el-table-column
              type="index"
              label="序号"
              width="70"
              :index="(index: number) => getIndex('outbound', index)"
              align="center"
            />
            <el-table-column
              prop="productName"
              label="产品名称"
              min-width="150"
            />
            <el-table-column
              prop="productNo"
              label="产品编号"
              min-width="140"
            />
            <el-table-column
              prop="specification"
              label="规格型号"
              min-width="140"
            />
            <el-table-column
              prop="unit"
              label="单位"
              width="90"
              align="center"
            />
            <el-table-column prop="batchNo" label="批次号" min-width="120" />
            <el-table-column label="有效期" min-width="120">
              <template #default="{ row }">
                {{ formatDate(row.expiryDate) }}
              </template>
            </el-table-column>
            <el-table-column label="出库日期" min-width="120">
              <template #default="{ row }">
                {{ formatDate(row.outboundDate) }}
              </template>
            </el-table-column>
            <el-table-column
              prop="outboundQuantity"
              label="出库数量"
              min-width="110"
              align="right"
            />
            <el-table-column
              prop="warehouseName"
              label="仓库名称"
              min-width="140"
            />
            <el-table-column
              prop="warehouseAreaName"
              label="库区名称"
              min-width="140"
            />
            <el-table-column
              prop="warehouseLocationName"
              label="库位名称"
              min-width="140"
            />
            <el-table-column
              prop="customerName"
              label="客户名称"
              min-width="150"
            />
            <el-table-column
              prop="salesOrderNo"
              label="销售单号"
              min-width="150"
            />
            <template #empty>
              <div class="empty-block">
                <p>暂无出库记录</p>
                <span>切换查询条件或稍后再试</span>
              </div>
            </template>
          </el-table>
          <div class="table-pagination">
            <div class="pagination-wrapper">
              <div class="pagination-info">
                <div class="pagination-info-item">
                  <el-icon class="info-icon"><Document /></el-icon>
                  <span class="pagination-text">
                    共
                    <span class="highlight-number">{{
                      outboundState.pagination.totalCount
                    }}</span>
                    条记录
                  </span>
                </div>
                <div class="pagination-info-item">
                  <el-icon class="info-icon"><Files /></el-icon>
                  <span class="pagination-text">
                    第
                    <span class="highlight-number">{{
                      outboundState.pagination.pageIndex
                    }}</span>
                    /
                    <span class="highlight-number">{{
                      outboundState.pagination.pageCount || 1
                    }}</span>
                    页
                  </span>
                </div>
              </div>
              <div class="pagination-controls">
                <el-button
                  size="small"
                  @click="gotoFirst('outbound')"
                  :disabled="outboundState.pagination.pageIndex === 1"
                  class="pagination-btn pagination-btn-first"
                >
                  首页
                </el-button>
                <el-button
                  size="small"
                  @click="gotoPrev('outbound')"
                  :disabled="outboundState.pagination.pageIndex === 1"
                  class="pagination-btn"
                >
                  上一页
                </el-button>
                <el-pagination
                  v-model:current-page="outboundState.pagination.pageIndex"
                  v-model:page-size="outboundState.pagination.pageSize"
                  :total="outboundState.pagination.totalCount"
                  layout="prev, pager, next"
                  :page-sizes="[10, 20, 30, 50]"
                  @current-change="(val: number) => handleCurrentChange('outbound', val)"
                  class="pagination-component"
                />
                <el-button
                  size="small"
                  @click="gotoNext('outbound')"
                  :disabled="
                    outboundState.pagination.pageIndex >=
                    outboundState.pagination.pageCount
                  "
                  class="pagination-btn"
                >
                  下一页
                </el-button>
                <el-button
                  size="small"
                  @click="gotoLast('outbound')"
                  :disabled="
                    outboundState.pagination.pageIndex >=
                    outboundState.pagination.pageCount
                  "
                  class="pagination-btn pagination-btn-last"
                >
                  尾页
                </el-button>
                <el-select
                  v-model="outboundState.pagination.pageSize"
                  size="small"
                  class="page-size-select"
                  @change="(val: number) => handleSizeChange('outbound', val)"
                >
                  <el-option label="10条/页" :value="10" />
                  <el-option label="20条/页" :value="20" />
                  <el-option label="30条/页" :value="30" />
                  <el-option label="50条/页" :value="50" />
                </el-select>
                <span class="pagination-jumper">前往</span>
                <el-input-number
                  v-model="outboundJumpPage"
                  :min="1"
                  :max="outboundState.pagination.pageCount || 1"
                  :controls="false"
                  size="small"
                  class="jump-input"
                  @keyup.enter="handleJumpPage('outbound')"
                />
                <span class="pagination-jumper">页</span>
              </div>
            </div>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-card>
  </div>
</template>

<script lang="ts" setup>
import {
  Box,
  Collection,
  Document,
  Download,
  Files,
  Operation,
  RefreshLeft,
  Search,
  Tickets,
} from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import moment from "moment";
import { computed, onMounted, reactive, ref, watch } from "vue";
import https from "@/Http/http";

type TabName = "inbound" | "outbound";

interface SearchFormState {
  keyword: string;
  productType: string | null;
  productAttribute: string | null;
  productCategory: string | null;
}

interface ProductMeta {
  productcard: string;
  productname: string;
  productmodelsame?: string;
  productunit?: string;
  producttypeid?: string | number | null;
  productattributeid?: string | number | null;
  productclassificationid?: string | number | null;
}

interface PaginationState {
  pageIndex: number;
  pageSize: number;
  totalCount: number;
  pageCount: number;
}

interface BaseRecord {
  id: number;
  productName: string;
  productNo: string;
  specification?: string;
  unit?: string;
  batchNo?: string;
  expiryDate?: string | null;
  productTypeId?: string | number | null;
  productAttributeId?: string | number | null;
  productCategoryId?: string | number | null;
}

interface InboundRecordRaw extends BaseRecord {
  inboundDate?: string | null;
  inboundQuantity?: number;
  warehouseName?: string;
  warehouseAreaName?: string;
  warehouseLocationName?: string;
  workOrderName?: string;
  workOrderNo?: string;
}

interface OutboundRecordRaw extends BaseRecord {
  outboundDate?: string | null;
  outboundQuantity?: number;
  warehouseName?: string;
  warehouseAreaName?: string;
  warehouseLocationName?: string;
  customerName?: string;
  salesOrderNo?: string;
}

type RecordWithMeta<T extends Record<string, any>> = T & {
  specification: string;
  unit: string;
  productTypeLabel: string;
  productTypeValue: string;
  productAttributeLabel: string;
  productAttributeValue: string;
  productCategoryLabel: string;
  productCategoryValue: string;
};

const searchForm = reactive<SearchFormState>({
  keyword: "",
  productType: null,
  productAttribute: null,
  productCategory: null,
});

const activeTab = ref<TabName>("inbound");
const loadingMeta = ref(false);
const inboundJumpPage = ref(1);
const outboundJumpPage = ref(1);

const productMeta = ref<ProductMeta[]>([]);
const productMetaMap = computed(() => {
  const map: Record<string, ProductMeta> = {};
  productMeta.value.forEach((item) => {
    const candidates = [item.productcard, item.productname];
    candidates.forEach((candidate) => {
      const key = normalizeKey(candidate);
      if (key && !map[key]) {
        map[key] = item;
      }
    });
  });
  return map;
});

const inboundState = reactive({
  loading: false,
  exportLoading: false,
  loaded: false,
  data: [] as InboundRecordRaw[],
  pagination: {
    pageIndex: 1,
    pageSize: 10,
    totalCount: 0,
    pageCount: 0,
  } as PaginationState,
});

const outboundState = reactive({
  loading: false,
  exportLoading: false,
  loaded: false,
  data: [] as OutboundRecordRaw[],
  pagination: {
    pageIndex: 1,
    pageSize: 10,
    totalCount: 0,
    pageCount: 0,
  } as PaginationState,
});

const hasMetaFilter = computed(
  () =>
    !!(
      searchForm.productType ||
      searchForm.productAttribute ||
      searchForm.productCategory
    )
);

const currentLoading = computed(() =>
  activeTab.value === "inbound" ? inboundState.loading : outboundState.loading
);

const productTypeOptions = computed(() =>
  buildOptionsFromMeta("producttypeid")
);
const productAttributeOptions = computed(() =>
  buildOptionsFromMeta("productattributeid")
);
const productCategoryOptions = computed(() =>
  buildOptionsFromMeta("productclassificationid")
);

const inboundDisplayList = computed(() =>
  filterWithMeta(enrichWithProductMeta(inboundState.data))
);
const outboundDisplayList = computed(() =>
  filterWithMeta(enrichWithProductMeta(outboundState.data))
);

const buildQueryParams = (pagination: PaginationState) => {
  const params: Record<string, unknown> = {
    PageIndex: pagination.pageIndex,
    PageSize: pagination.pageSize,
  };
  if (searchForm.keyword) {
    params.ProductKeyword = searchForm.keyword.trim();
  }
  return params;
};

const fetchProductMeta = async () => {
  loadingMeta.value = true;
  try {
    const res = await https.Reads.get("/Product/ProductGetList", {
      params: {
        pageindex: 1,
        pagesize: 9999,
      },
    });
    const payload = res?.data ?? {};
    const code = payload.code ?? payload.Code ?? 0;
    if (code !== 1) {
      throw new Error(payload.msg ?? payload.Msg ?? "获取产品信息失败");
    }
    const list =
      payload.data ?? payload.Data ?? (Array.isArray(payload) ? payload : []);
    productMeta.value = Array.isArray(list) ? list : [];
  } catch (error: any) {
    console.error("获取产品信息失败:", error);
    ElMessage.error(error?.message ?? "获取产品信息失败，请稍后重试");
    productMeta.value = [];
  } finally {
    loadingMeta.value = false;
  }
};

const loadInboundRecords = async () => {
  inboundState.loading = true;
  try {
    const res = await https.Reads.get("/Warehouse/ProductStorageList", {
      params: buildQueryParams(inboundState.pagination),
    });
    const { list, totalCount, pageCount } = parseListResponse(res);
    inboundState.data = list.map(normalizeInboundRecord);
    inboundState.pagination.totalCount = totalCount;
    inboundState.pagination.pageCount = pageCount;
    inboundState.loaded = true;
  } catch (error: any) {
    handleError(error, "获取入库记录失败");
    inboundState.data = [];
    inboundState.pagination.totalCount = 0;
  } finally {
    inboundState.loading = false;
  }
};

const loadOutboundRecords = async () => {
  outboundState.loading = true;
  try {
    const res = await https.Reads.get("/Warehouse/SalesOutboundList", {
      params: buildQueryParams(outboundState.pagination),
    });
    const { list, totalCount, pageCount } = parseListResponse(res);
    outboundState.data = list.map(normalizeOutboundRecord);
    outboundState.pagination.totalCount = totalCount;
    outboundState.pagination.pageCount = pageCount;
    outboundState.loaded = true;
  } catch (error: any) {
    handleError(error, "获取出库记录失败");
    outboundState.data = [];
    outboundState.pagination.totalCount = 0;
  } finally {
    outboundState.loading = false;
  }
};

const handleTabChange = (name: TabName) => {
  if (name === "outbound" && !outboundState.loaded) {
    loadOutboundRecords();
  }
  if (name === "inbound" && !inboundState.loaded) {
    loadInboundRecords();
  }
};

const handleSearch = () => {
  const target = activeTab.value === "inbound" ? inboundState : outboundState;
  target.pagination.pageIndex = 1;
  if (activeTab.value === "inbound") {
    loadInboundRecords();
  } else {
    loadOutboundRecords();
  }
};

const handleReset = () => {
  searchForm.keyword = "";
  searchForm.productType = null;
  searchForm.productAttribute = null;
  searchForm.productCategory = null;
  handleSearch();
};

const handleSizeChange = (tab: TabName, size: number) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  target.pagination.pageSize = size;
  target.pagination.pageIndex = 1;
  jumpPageRef.value = 1;
  tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
};

const handleCurrentChange = (tab: TabName, page: number) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  target.pagination.pageIndex = page;
  jumpPageRef.value = page;
  tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
};

const gotoFirst = (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  target.pagination.pageIndex = 1;
  jumpPageRef.value = 1;
  tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
};

const gotoPrev = (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  if (target.pagination.pageIndex > 1) {
    target.pagination.pageIndex--;
    jumpPageRef.value = target.pagination.pageIndex;
    tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
  }
};

const gotoNext = (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  if (target.pagination.pageIndex < target.pagination.pageCount) {
    target.pagination.pageIndex++;
    jumpPageRef.value = target.pagination.pageIndex;
    tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
  }
};

const gotoLast = (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  target.pagination.pageIndex = target.pagination.pageCount || 1;
  jumpPageRef.value = target.pagination.pageIndex;
  tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
};

const handleJumpPage = (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  const jumpPageRef = tab === "inbound" ? inboundJumpPage : outboundJumpPage;
  const maxPage = target.pagination.pageCount || 1;
  if (jumpPageRef.value >= 1 && jumpPageRef.value <= maxPage) {
    target.pagination.pageIndex = jumpPageRef.value;
    tab === "inbound" ? loadInboundRecords() : loadOutboundRecords();
  } else {
    ElMessage.warning(`请输入1到${maxPage}之间的页码`);
    jumpPageRef.value = target.pagination.pageIndex;
  }
};

const handleExport = async (tab: TabName) => {
  const target = tab === "inbound" ? inboundState : outboundState;
  if (target.exportLoading) {
    return;
  }
  target.exportLoading = true;
  try {
    const params: Record<string, unknown> = {};
    if (searchForm.keyword) {
      params.ProductKeyword = searchForm.keyword.trim();
    }
    const url =
      tab === "inbound"
        ? "/Warehouse/ProductStorageExport"
        : "/Warehouse/SalesOutboundExport";
    const response = await https.Reads.get(url, {
      params,
      responseType: "blob",
    });
    downloadBlob(response.data, tab === "inbound" ? "入库记录" : "出库记录");
  } catch (error: any) {
    handleError(
      error,
      tab === "inbound" ? "导出入库记录失败" : "导出出库记录失败"
    );
  } finally {
    target.exportLoading = false;
  }
};

const normalizeInboundRecord = (item: any): InboundRecordRaw => {
  const rawWarehouseName =
    item.warehouseDisplayName ??
    item.WarehouseDisplayName ??
    item.warehouseName ??
    item.WarehouseName ??
    "";
  const { warehouse, reservoir, seat } =
    splitWarehouseLocation(rawWarehouseName);

  return {
    id: Number(item.id ?? item.Id ?? 0),
    productName: item.productName ?? item.ProductName ?? "",
    productNo: item.productNo ?? item.ProductNo ?? "",
    specification: item.specification ?? item.Specification ?? "",
    unit: item.unit ?? item.Unit ?? "",
    batchNo: item.batchNo ?? item.BatchNo ?? "",
    expiryDate: item.expiryDate ?? item.ExpiryDate ?? null,
    inboundDate: item.inboundDate ?? item.InboundDate ?? null,
    inboundQuantity: Number(item.inboundQuantity ?? item.InboundQuantity ?? 0),
    warehouseName: warehouse || rawWarehouseName,
    warehouseAreaName:
      item.reservoirDisplayName ??
      item.ReservoirDisplayName ??
      item.warehouseAreaName ??
      reservoir,
    warehouseLocationName:
      item.seatDisplayName ??
      item.SeatDisplayName ??
      item.warehouseLocationName ??
      seat,
    workOrderName: item.workOrderName ?? item.WorkOrderName ?? "",
    workOrderNo: item.workOrderNo ?? item.WorkOrderNo ?? "",
    productTypeId: item.productTypeId ?? item.ProductTypeId ?? null,
    productAttributeId:
      item.productAttributeId ?? item.ProductAttributeId ?? null,
    productCategoryId: item.productCategoryId ?? item.ProductCategoryId ?? null,
  };
};

const normalizeOutboundRecord = (item: any): OutboundRecordRaw => {
  const rawWarehouseName =
    item.warehouseDisplayName ??
    item.WarehouseDisplayName ??
    item.warehouseName ??
    item.WarehouseName ??
    "";
  const { warehouse, reservoir, seat } =
    splitWarehouseLocation(rawWarehouseName);

  return {
    id: Number(item.id ?? item.Id ?? 0),
    productName: item.productName ?? item.ProductName ?? "",
    productNo: item.productNo ?? item.ProductNo ?? "",
    specification: item.specification ?? item.Specification ?? "",
    unit: item.unit ?? item.Unit ?? "",
    batchNo:
      item.batchNo ?? item.BatchNo ?? item.batchNoId ?? item.BatchNoId ?? "",
    expiryDate: item.expiryDate ?? item.ExpiryDate ?? null,
    outboundDate: item.outboundDate ?? item.OutboundDate ?? null,
    outboundQuantity: Number(
      item.outboundQuantity ?? item.OutboundQuantity ?? 0
    ),
    warehouseName: warehouse || rawWarehouseName,
    warehouseAreaName:
      item.reservoirDisplayName ??
      item.ReservoirDisplayName ??
      item.warehouseAreaName ??
      reservoir,
    warehouseLocationName:
      item.seatDisplayName ??
      item.SeatDisplayName ??
      item.warehouseLocationName ??
      seat,
    customerName: item.machineName ?? item.MachineName ?? "",
    salesOrderNo: item.salesOrderNo ?? item.SalesOrderNo ?? "",
    productTypeId: item.productTypeId ?? item.ProductTypeId ?? null,
    productAttributeId:
      item.productAttributeId ?? item.ProductAttributeId ?? null,
    productCategoryId: item.productCategoryId ?? item.ProductCategoryId ?? null,
  };
};

function findProductMeta(record: BaseRecord) {
  const keyByNo = normalizeKey(record.productNo);
  if (keyByNo && productMetaMap.value[keyByNo]) {
    return productMetaMap.value[keyByNo];
  }
  const keyByName = normalizeKey(record.productName);
  if (keyByName && productMetaMap.value[keyByName]) {
    return productMetaMap.value[keyByName];
  }
  return undefined;
}

const enrichWithProductMeta = <T extends BaseRecord>(records: T[]) =>
  records.map((record) => {
    const meta = findProductMeta(record);
    const { label: typeLabel, value: typeValue } = resolveMetaField(
      meta?.producttypeid,
      record.productTypeId
    );
    const { label: attrLabel, value: attrValue } = resolveMetaField(
      meta?.productattributeid,
      record.productAttributeId
    );
    const { label: categoryLabel, value: categoryValue } = resolveMetaField(
      meta?.productclassificationid,
      record.productCategoryId
    );
    return {
      ...record,
      specification: record.specification || meta?.productmodelsame || "",
      unit: record.unit || meta?.productunit || "",
      productTypeLabel: typeLabel,
      productTypeValue: typeValue,
      productAttributeLabel: attrLabel,
      productAttributeValue: attrValue,
      productCategoryLabel: categoryLabel,
      productCategoryValue: categoryValue,
    } as RecordWithMeta<T>;
  });

const filterWithMeta = (records: RecordWithMeta<any>[]) =>
  records.filter((record) => {
    const typeMatch = searchForm.productType
      ? record.productTypeValue === searchForm.productType
      : true;
    const attrMatch = searchForm.productAttribute
      ? record.productAttributeValue === searchForm.productAttribute
      : true;
    const categoryMatch = searchForm.productCategory
      ? record.productCategoryValue === searchForm.productCategory
      : true;
    return typeMatch && attrMatch && categoryMatch;
  });

const parseListResponse = (res: any) => {
  const payload = res?.data ?? {};
  const code = payload.code ?? payload.Code ?? 1;
  if (code === -1 || code === 0) {
    throw new Error(payload.msg ?? payload.Msg ?? "请求失败");
  }
  const list =
    payload.data ?? payload.Data ?? (Array.isArray(payload) ? payload : []);
  const totalCount =
    payload.totalCount ??
    payload.TotalCount ??
    (Array.isArray(list) ? list.length : 0);
  const pageCount = payload.pageCount ?? payload.PageCount ?? 0;
  return {
    list: Array.isArray(list) ? list : [],
    totalCount,
    pageCount,
  };
};

const buildOptionsFromMeta = (field: keyof ProductMeta) => {
  const optionMap = new Map<string, string>();
  productMeta.value.forEach((meta) => {
    const value = normalizeField(meta[field]);
    if (value && !optionMap.has(value)) {
      optionMap.set(value, value);
    }
  });
  return Array.from(optionMap.entries()).map(([value, label]) => ({
    value,
    label,
  }));
};

const resolveMetaField = (
  metaValue: unknown,
  fallbackValue: unknown
): { label: string; value: string } => {
  const candidate = normalizeField(metaValue) || normalizeField(fallbackValue);
  return {
    label: candidate || "-",
    value: candidate,
  };
};

const normalizeField = (value: unknown) => {
  if (value === undefined || value === null) return "";
  const str = String(value).trim();
  return str;
};

const splitWarehouseLocation = (value?: string) => {
  const parts = (value ?? "")
    .split(/[\s\/\-—>]+/)
    .map((item) => item.trim())
    .filter(Boolean);
  return {
    warehouse: parts[0] ?? "",
    reservoir: parts[1] ?? "",
    seat: parts[2] ?? "",
  };
};

const normalizeKey = (value?: string) => {
  if (!value) return "";
  return value.trim().toLowerCase();
};

const formatDate = (date?: string | null) => {
  if (!date) return "-";
  return moment(date).format("YYYY-MM-DD");
};

const getIndex = (tab: TabName, index: number) => {
  const pagination =
    tab === "inbound" ? inboundState.pagination : outboundState.pagination;
  return (pagination.pageIndex - 1) * pagination.pageSize + index + 1;
};

const downloadBlob = (blobData: Blob, prefix: string) => {
  const blob = new Blob([blobData], {
    type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  const timestamp = moment().format("YYYYMMDDHHmmss");
  link.href = url;
  link.download = `${prefix}_${timestamp}.xlsx`;
  link.click();
  URL.revokeObjectURL(url);
};

const handleError = (error: any, fallback: string) => {
  console.error(fallback, error);
  ElMessage.error(error?.message ?? fallback);
};

onMounted(async () => {
  await fetchProductMeta();
  await loadInboundRecords();
  // 初始化跳转页码
  inboundJumpPage.value = 1;
  outboundJumpPage.value = 1;
});

// 监听分页变化，同步跳转页码
watch(
  () => inboundState.pagination.pageIndex,
  (val) => {
    inboundJumpPage.value = val;
  }
);

watch(
  () => outboundState.pagination.pageIndex,
  (val) => {
    outboundJumpPage.value = val;
  }
);
</script>

<style scoped>
.record-page {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding-bottom: 24px;
  background: #f5f7fa;
  min-height: 100vh;
}

.search-card,
.tabs-card {
  border-radius: 14px;
  border: none;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  background: #fff;
}

.search-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid #f0f2f5;
  margin-bottom: 12px;
}

.search-header__title {
  display: flex;
  align-items: center;
  gap: 12px;
}

.search-header__icon {
  font-size: 30px;
  color: #409eff;
}

.search-header__subtitle {
  margin: 0;
  color: #909399;
  font-size: 14px;
}

.search-header__heading {
  margin: 0;
  font-size: 22px;
  font-weight: 600;
}

.search-header__actions {
  display: flex;
  gap: 10px;
}

.search-form {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.search-input {
  width: 220px;
}

.tab-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 10px 0 18px;
}

.tab-toolbar__info h3 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 18px;
  font-weight: 600;
}

.tab-toolbar__info p {
  margin: 6px 0 0;
  color: #909399;
  font-size: 14px;
}

.record-table {
  border-radius: 8px;
  overflow: hidden;
}

.empty-block {
  padding: 40px 0;
  text-align: center;
  color: #909399;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.table-pagination {
  margin-top: 24px;
  padding: 24px 28px;
  background: linear-gradient(
    135deg,
    rgba(79, 172, 254, 0.06) 0%,
    rgba(0, 242, 254, 0.04) 100%
  );
  border-radius: 14px;
  border: 1px solid rgba(79, 172, 254, 0.15);
  box-shadow: 0 2px 12px rgba(79, 172, 254, 0.08);
  transition: all 0.3s ease;
}

.table-pagination:hover {
  box-shadow: 0 4px 16px rgba(79, 172, 254, 0.12);
  border-color: rgba(79, 172, 254, 0.25);
}

.pagination-wrapper {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 20px;
}

.pagination-info {
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
}

.pagination-info-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: rgba(255, 255, 255, 0.8);
  border-radius: 8px;
  border: 1px solid rgba(79, 172, 254, 0.2);
  transition: all 0.3s ease;
}

.pagination-info-item:hover {
  background: rgba(255, 255, 255, 1);
  border-color: rgba(79, 172, 254, 0.4);
  transform: translateY(-2px);
  box-shadow: 0 2px 8px rgba(79, 172, 254, 0.15);
}

.info-icon {
  font-size: 16px;
  color: #4facfe;
}

.pagination-text {
  font-size: 14px;
  color: #606266;
  font-weight: 400;
}

.highlight-number {
  color: #4facfe;
  font-weight: 700;
  font-size: 15px;
  margin: 0 2px;
}

.pagination-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.pagination-btn {
  border-radius: 8px;
  padding: 10px 18px;
  font-weight: 500;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border: 1px solid rgba(79, 172, 254, 0.3);
  background: linear-gradient(135deg, #ffffff 0%, #f8fbff 100%);
  color: #4facfe;
  box-shadow: 0 2px 6px rgba(79, 172, 254, 0.1);
}

.pagination-btn:hover:not(:disabled) {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: #fff;
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(79, 172, 254, 0.3);
}

.pagination-btn:active:not(:disabled) {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(79, 172, 254, 0.2);
}

.pagination-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: #f5f7fa;
  color: #c0c4cc;
  border-color: #e4e7ed;
  box-shadow: none;
}

.pagination-btn-first,
.pagination-btn-last {
  font-weight: 600;
}

.pagination-component {
  flex: 0 0 auto;
}

.pagination-component :deep(.el-pagination) {
  display: flex;
  align-items: center;
  gap: 8px;
}

.pagination-component :deep(.el-pagination__sizes) {
  margin-right: 0;
}

.pagination-component :deep(.el-pagination .el-select .el-input__inner) {
  border-radius: 8px;
  border: 1px solid rgba(79, 172, 254, 0.3);
  transition: all 0.3s ease;
}

.pagination-component :deep(.el-pagination .el-select .el-input__inner:hover) {
  border-color: rgba(79, 172, 254, 0.5);
}

.pagination-component :deep(.el-pager li) {
  border-radius: 8px;
  margin: 0 2px;
  min-width: 36px;
  height: 36px;
  line-height: 36px;
  transition: all 0.3s ease;
  border: 1px solid transparent;
}

.pagination-component :deep(.el-pager li:hover) {
  background: rgba(79, 172, 254, 0.1);
  border-color: rgba(79, 172, 254, 0.3);
  transform: translateY(-2px);
  box-shadow: 0 2px 8px rgba(79, 172, 254, 0.15);
}

.pagination-component :deep(.el-pager li.is-active) {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: #fff;
  border-color: transparent;
  font-weight: 600;
  box-shadow: 0 2px 8px rgba(79, 172, 254, 0.3);
}

.pagination-component :deep(.btn-prev),
.pagination-component :deep(.btn-next) {
  border-radius: 8px;
  margin: 0 4px;
  min-width: 36px;
  height: 36px;
  transition: all 0.3s ease;
  border: 1px solid rgba(79, 172, 254, 0.3);
  background: rgba(255, 255, 255, 0.9);
}

.pagination-component :deep(.btn-prev:hover),
.pagination-component :deep(.btn-next:hover) {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: #fff;
  border-color: transparent;
  transform: translateY(-2px);
  box-shadow: 0 2px 8px rgba(79, 172, 254, 0.2);
}

.pagination-component :deep(.btn-prev:disabled),
.pagination-component :deep(.btn-next:disabled) {
  opacity: 0.5;
  cursor: not-allowed;
  background: #f5f7fa;
  color: #c0c4cc;
  border-color: #e4e7ed;
}

.page-size-select {
  width: 110px;
  border-radius: 6px;
}

.page-size-select :deep(.el-input__inner) {
  border-radius: 6px;
  border: 1px solid rgba(79, 172, 254, 0.3);
  transition: all 0.3s ease;
}

.page-size-select :deep(.el-input__inner:hover) {
  border-color: rgba(79, 172, 254, 0.5);
}

.pagination-jumper {
  color: #606266;
  font-size: 14px;
  white-space: nowrap;
}

.jump-input {
  width: 70px;
}

.jump-input :deep(.el-input__wrapper) {
  border-radius: 6px;
  border: 1px solid rgba(79, 172, 254, 0.3);
  transition: all 0.3s ease;
}

.jump-input :deep(.el-input__wrapper:hover) {
  border-color: rgba(79, 172, 254, 0.5);
}

.jump-input :deep(.el-input__wrapper.is-focus) {
  border-color: #4facfe;
  box-shadow: 0 0 0 2px rgba(79, 172, 254, 0.1);
}

@media (max-width: 1024px) {
  .search-input {
    width: 100%;
  }
  .tab-toolbar {
    flex-direction: column;
    align-items: flex-start;
  }
  .pagination-wrapper {
    flex-direction: column;
    align-items: stretch;
  }
  .pagination-controls {
    justify-content: center;
  }
}
</style>
